package server;

import java.io.IOException;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;

import server.interfaces.IMobileAgentCommunicationChannelSender;
import server.interfaces.IMobileAgentExecutionEngine;

import com.Constants;
import com.Event;
import com.LedsManager;
import com.ParamsLabel;
import com.sun.spot.io.j2me.radiogram.RadiogramConnection;
import com.sun.spot.resources.transducers.LEDColor;

public class MobileAgentCommunicationChannelSender implements IMobileAgentCommunicationChannelSender {
	
	
	private Vector communicationEvents;

	private IMobileAgentExecutionEngine executionEngine = null;
	
	private String communicationPort = null;
	
	/**
	 * Creates a MobileAgentCommunicationChannelSender
	 * @param executionEngine IMobileAgentExecutionEngine component
	 * @param communicationPort Communication Port number
	 */
	public MobileAgentCommunicationChannelSender (IMobileAgentExecutionEngine executionEngine, String communicationPort) {
		this.executionEngine = executionEngine;
		this.communicationEvents = new Vector();
		this.communicationPort = communicationPort;
	}

	public synchronized void send(Event event) {		
		this.communicationEvents.addElement(event);
		this.notifyAll();
	}
	
	/**
	 * Needs to send a set of events after a successful migration
	 * @param events set of events
	 */
	public synchronized void send(Vector events) {
		for (int i = 0; i < events.size(); i++) {
			this.communicationEvents.addElement(events.elementAt(i));
		}
		this.notifyAll();
	}
	
	public void run() {
		while(true){
			waitForCommunications();
			while (this.communicationEvents.size() > 0) {
				Event event = (Event)this.communicationEvents.firstElement();
				byte evtName = event.getName(); 
				RadiogramConnection conn = null;
				Datagram dg = null;
				try {
					switch(evtName) {
						case Event.MGR_REQUEST:
						case Event.MGR_ACK:
						case Event.MGR_EXECUTED:
							conn = (RadiogramConnection)Connector.open("radiogram://" + event.getParam(ParamsLabel.EVT_ADDRESS) + ":" + this.communicationPort);
							dg = conn.newDatagram(conn.getMaximumLength());
							dg.writeUTF(evtName + Constants.COMMUNICATION_SEPARATOR + (String)event.getParam(ParamsLabel.AGT_NAME));
							break;
						case Event.DSC_PUBLISH:
							conn = (RadiogramConnection)Connector.open("radiogram://broadcast:" + this.communicationPort);
							dg = conn.newDatagram(conn.getMaximumLength());
							dg.writeUTF(evtName + Constants.COMMUNICATION_SEPARATOR);
							break;
						case Event.DSC_ANSWER:
							conn = (RadiogramConnection)Connector.open("radiogram://" + event.getTargetID() + ":" + this.communicationPort);
							dg = conn.newDatagram(conn.getMaximumLength());
							dg.writeUTF(evtName + this.agentsToString());
							break;		
						case Event.DSC_REFRESH:
							conn = (RadiogramConnection)Connector.open("radiogram://broadcast:" + this.communicationPort);
							dg = conn.newDatagram(conn.getMaximumLength());
							dg.writeUTF(evtName + Constants.COMMUNICATION_SEPARATOR + event.getParam(ParamsLabel.AGT_NAME));
							break;
						case Event.MSG_TO_BASESTATION:
							conn = (RadiogramConnection)Connector.open("radiogram://" + event.getParam(ParamsLabel.AGT_BASESTATION_ADDRESS) + ":" + this.communicationPort);
							dg = conn.newDatagram(conn.getMaximumLength());
							dg.writeUTF(evtName + Constants.COMMUNICATION_SEPARATOR + event.toString());
							break;
						case Event.AGN_CREATION:
						case Event.MSG:
						default:
							conn = (RadiogramConnection)Connector.open("radiogram://" + event.getParam(ParamsLabel.AGT_ADDRESS) + ":" + this.communicationPort);
							dg = conn.newDatagram(conn.getMaximumLength());
							dg.writeUTF(evtName + Constants.COMMUNICATION_SEPARATOR + event.toString());
							break;
					}
					conn.send(dg);
					
					LedsManager.radioTransmission(true,false);	
					this.communicationEvents.removeElementAt(0);
				}
				catch (Exception e) {
					e.printStackTrace();
					LedsManager.error(LEDColor.BLUE);					
				}
				finally {
					
					try {
						conn.close();
					}
					catch (IOException e) {
						LedsManager.error(LEDColor.BLUE);
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	/**
	 * This method waits for events to send, by a "wait-notify" mechanism
	 */
	private  synchronized void waitForCommunications() {
		while (this.communicationEvents.size() == 0) {
			try {
				wait();
			}
			catch (InterruptedException e) {
				LedsManager.error(LEDColor.BLUE);
				e.printStackTrace();
			}
		}
		
	}

	/**
	 * Converts an Agent object in a String object
	 * @return Agent "toString"
	 */
	private String agentsToString() {
		
		Vector vectorAgents = this.executionEngine.getLocalAgentsID();
		String stringAgents = "";
		if (vectorAgents.size() > 0 ) {			
			stringAgents = Constants.COMMUNICATION_SEPARATOR;
			for (int i = 0; i < vectorAgents.size(); i++) {
				stringAgents += (String)vectorAgents.elementAt(i) + Constants.COMMUNICATION_SEPARATOR;
			}
		}
		return stringAgents;
	}
}

